from pyglet.gl import *
from windoh import Renderer

def rect(x, y, w, h, mode=GL_QUADS):
    glBegin(mode)
    #glTexCoord2f (0.0, 1.0);
    glVertex2i(x, y)
    #glTexCoord2f(1.0, 1.0);
    glVertex2i(x+w, y)
    #glTexCoord2f(1.0, 0.0);
    glVertex2i(x+w, y+h)
    #glTexCoord2f(0.0, 0.0);
    glVertex2i(x, y+h)
    glEnd ()

def rectgradvert(x, y, w, h, c1, c2):
    glBegin(GL_QUADS)
    glColor3f(*c1)
    glVertex2i(x, y)
    #glTexCoord2f(1.0, 1.0);
    glColor3f(*c1)
    glVertex2i(x+w, y)
    #glTexCoord2f(1.0, 0.0);
    glColor3f(*c2)
    glVertex2i(x+w, y+h)
    #glTexCoord2f(0.0, 0.0);
    glColor3f(*c2)
    glVertex2i(x, y+h)
    glEnd ()

def rectgradhoriz(x, y, w, h, c1, c2):
    glBegin(GL_QUADS)
    glColor3f(*c1)
    glVertex2i(x, y)
    #glTexCoord2f(1.0, 1.0);
    glColor3f(*c2)
    glVertex2i(x+w, y)
    #glTexCoord2f(1.0, 0.0);
    glColor3f(*c2)
    glVertex2i(x+w, y+h)
    #glTexCoord2f(0.0, 0.0);
    glColor3f(*c1)
    glVertex2i(x, y+h)
    glEnd ()


def requires(*keys):
    def wrap_func(func):
        func.requires = keys
        return func
    return wrap_func


class ControlRenderer(object):

    def _run_func(self, name, control, context, cs):
        try:
            func = getattr(self, name)
        except AttributeError:
            print "cant do %s" % name
        else:
            if hasattr(func, 'requires'):
                ok = True
                for thing in func.requires:
                    if cs[thing] is None:
                        ok = False
                if ok:
                    func(control, context, cs)
            else:
                func(control, context, cs)

    def __call__(self, control, context):
        cs = control._computed_style
        assert(cs is not None)

        self._run_func('render_background_style', control, context, cs)
        self._run_func('render_background_image', control, context, cs)
        self._run_func('render_border_style', control, context, cs)

    @requires('background_style')
    def render_background_style(self, control, context, cs):
        self._run_func('render_background_style_'+cs['background_style'], 
            control, context, cs)

    @requires('border_style', 'border_width', 'border_color')
    def render_border_style(self, control, context, cs):
        glLineWidth(cs['border_width'])
        glColor3f(*cs['border_color'])

        self._run_func('render_border_style_'+cs['border_style'], 
            control, context, cs)

    @requires('background_color')
    def render_background_style_solid(self, control, context, cs):
        #if cs['background_color']:
        glColor3f(*cs['background_color'])
        rect(cs['left'], cs['bottom'], cs['width']-1, cs['height']-1)       
        
    @requires('background_image')
    def render_background_image(self, control, context, cs):
        #if cs['background_image']:
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
        glEnable(GL_BLEND)
        glColor3f(1.0, 1.0, 1.0)
        cs['background_image'].blit(cs['left']+cs['background_image_left'], 
                                    cs['bottom']+cs['background_image_bottom'])
        glDisable(GL_BLEND)

    @requires('background_color', 'background_color2')
    def render_background_style_gradient_vert(self, control, context, cs):
        #if cs['background_color'] and cs['background_color2']:
        rectgradvert(cs['left'], cs['bottom'], cs['width']-1, cs['height']-1,
            cs['background_color'], cs['background_color2'])       

    @requires('background_color', 'background_color2')
    def render_background_style_gradient_horiz(self, control, context, cs):
        #if cs['background_color'] and cs['background_color2']:
        rectgradhoriz(cs['left'], cs['bottom'], cs['width']-1, cs['height']-1,
            cs['background_color'], cs['background_color2'])       

    def render_border_style_solid(self, control, context, cs):
        rect(cs['left'], cs['bottom'], cs['width']-1, cs['height']-1, GL_LINE_LOOP)

    def render_border_style_inset(self, control, context, cs):
        glBegin(GL_LINE_STRIP)
        glVertex2i(cs['left'], cs['bottom'])
        glVertex2i(cs['left']+cs['width']-1, cs['bottom'])
        glVertex2i(cs['left']+cs['width']-1, cs['bottom']+cs['height']-1)
        glEnd()
        
        bc = cs['border_color']
        r = max(0.0, bc[0] - 0.5)
        g = max(0.0, bc[1] - 0.5)
        b = max(0.0, bc[2] - 0.5)

        glColor3f(r, g, b)
        glBegin(GL_LINE_STRIP)
        glVertex2i(cs['left'], cs['bottom'])
        glVertex2i(cs['left'], cs['bottom']+cs['height']-1)
        glVertex2i(cs['left']+cs['width']-1, cs['bottom']+cs['height']-1)
        glEnd()

    def render_border_style_outset(self, control, context, cs):
        glBegin(GL_LINE_STRIP)
        glVertex2i(cs['left'], cs['bottom'])
        glVertex2i(cs['left'], cs['bottom']+cs['height']-1)
        glVertex2i(cs['left']+cs['width']-1, cs['bottom']+cs['height']-1)
        glEnd()
        
        bc = cs['border_color']
        r = max(0.0, bc[0] - 0.5)
        g = max(0.0, bc[1] - 0.5)
        b = max(0.0, bc[2] - 0.5)

        glColor3f(r, g, b)
        glBegin(GL_LINE_STRIP)
        glVertex2i(cs['left'], cs['bottom'])
        glVertex2i(cs['left']+cs['width']-1, cs['bottom'])
        glVertex2i(cs['left']+cs['width']-1, cs['bottom']+cs['height']-1)
        glEnd()
     

class LabelRenderer(ControlRenderer):
   def __call__(self, control, context):
        ControlRenderer.__call__(self, control, context) 

        if not control.label:
            return 

        cs = control._computed_style
        label = getattr(context, 'label', None)

        if label is None or control._dirty:
            ta = cs['text_align'] or 'left'
            x = cs['left']
            if ta == 'center':
                x += cs['width'] / 2
            elif ta == 'right':
                x += cs['width']

            label = context.label = \
                pyglet.text.Label(control.label, 
                    font_size=cs['font_size'],
                    font_name=cs['font_name'],
                    bold=cs['font_bold'],
                    italic=cs['font_italic'],
                    #color=cs['color'] or (255, 255, 255),
                    color=(0, 0, 0, 255),
                    valign='center', #cs['valign'] or 'bottom',
                    halign=ta, #cs['text_align'] or 'left',
                    x=x, #cs['left'],#+(cs['width']/2), 
                    y=cs['bottom']+(cs['height']/2),
                )
        
        label.draw()


class TextInputRenderer(ControlRenderer):
    def __call__(self, control, context):
        ControlRenderer.__call__(self, control, context)

        if not control._text:
            return 

        cs = control._computed_style
        layout = control.layout

        if True: #control.dirty:
            layout.x = cs['left']
            layout.y = 100 #cs['bottom']+cs['height']
            layout.width = cs['width']  
            layout.height = cs['height']
        layout.draw()

 
class ResizeHandlerRenderer(ControlRenderer):
    def __call__(self, control, context):
        ControlRenderer.__call__(self, control, context)
        cs = control._computed_style
        if cs['color']:
            glColor3f(*cs['color'])
            glLineWidth(1.0)
            glBegin(GL_LINES)
            d = cs['client_width'] / 3
            for i in range(1, 4):
                p = d*i
                if control.corner == 0:
                    glVertex2i(cs['client_x'], cs['client_y']+p)
                    glVertex2i(cs['client_x']+p, cs['client_y'])
                elif control.corner == 1:
                    glVertex2i(cs['client_x']+cs['client_width'], cs['client_y']+p)
                    glVertex2i(cs['client_x']+cs['client_width']-p, cs['client_y'])
                elif control.corner == 2:
                    glVertex2i(cs['client_x']+cs['client_width'], cs['client_y']+cs['client_height']-p)
                    glVertex2i(cs['client_x']+cs['client_width']-p, cs['client_y']+cs['client_height'])
                elif control.corner == 3:
                    glVertex2i(cs['client_x'], cs['client_y']+p)
                    glVertex2i(cs['client_x']+cs['client_width']-p, cs['client_y']+cs['client_height'])
                    
            glEnd()


class ImageRenderer(ControlRenderer):
    def __call__(self, control, context):
        ControlRenderer.__call__(self, control, context)
        cs = control._computed_style
        
        control.image.blit(cs['client_x'], cs['client_y'])


class OpenGLRenderer(Renderer):
    def __init__(self, **initial):
        default = dict(
            Control=ControlRenderer(),
            Label=LabelRenderer(),
            WindowResizeHandle=ResizeHandlerRenderer(),
            TextInput=TextInputRenderer(),
        )
        default.update(initial)
        Renderer.__init__(self, **default)

        self.stencil_stack = []

    def push_stencil(self, x, y, w, h):
        try:
            lx, ly, lw, lh = self.stencil_stack[-1]
        except IndexError:
            self.stencil_stack.append((x, y, w, h))
            return 
        
        if x > lx:
            nx = x
        else:
            nx = lx
        if y > ly:
            ny = y
        else:
            ny = ly
        if x + w < lx + lw:
            nw = w
        else: 
            nw = lw
        if y + h < ly + lh:
            nh = h
        else:
            nh = lh

        self.stencil_stack.append((nx, ny, nw, nh))

    def pop_stencil(self):
        self.stencil_stack.pop()

    def render_children(self, control):
        cs = control._computed_style

        if cs['overflow'] == 'clip':
            self.push_stencil(cs['screen_x']+cs['client_x'],
                              cs['screen_y']+cs['client_y'], 
                              cs['client_width'], 
                              cs['client_height'])
            ss = self.stencil_stack[-1]
            glEnable(GL_SCISSOR_TEST)
            glScissor(*ss)
        glPushMatrix()
        glTranslatef(cs['left'] + cs['client_x'], 
                     cs['bottom'] + cs['client_y'], 
                     0.0)
        Renderer.render_children(self, control)
        glPopMatrix()
        if cs['overflow'] == 'clip':
            self.pop_stencil()
            try:
                ss = self.stencil_stack[-1]
                glScissor(*ss)
            except IndexError:  
                glDisable(GL_SCISSOR_TEST)



